<?php
/**
 * Automatic correction of the language for words in the text because of the wrong keyboard layout
 * Автоматическое исправление языка для слов в тексте из-за неправильной раскладки клавиатуры
 *
 * Purpose
 *   * Корректировка поисковых запросов
 *   * Корректировка существующих и новых текстов, публикуемых посетителями на веб-сайтах.
 *
 * Features
 *   * Режим SIMILAR_CHARS. Исправление ошибочно набранных букв в словах, которые выглядят
 *     одинаково в разных раскладках клавиатуры. Незаметные латинские буквы среди русских
 *     исправляются в русские и наоборот. Алгоритм работает достаточно надёжно и быстро.
 *   * Режим KEYBOARD_LAYOUT. Исправление ошибочно набранных слов в другой раскладке клавиатуры.
 *     Для определения языка используются N-граммы. Алгоритм может иногда ошибаться,
 *     работает в разы медленнее, чем SIMILAR_CHARS. Алгоритм постоянно совершенствуется.
 *     Для поддержания качества существует тестовый набор слов, который в поставку не входит.
 *   * Двухстороннее исправление слов для русского и английского языка.
 *   * Исправление слов на смешанном языке.
 *   * Кодировка символов — UTF-8.
 *   * Класс может работать без расширений mbstring и iconv!
 *
 * Examples
 *   "\xd1\x81\xd0\xbesm\xd0\xbe" => 'cosmo' (2 первых и последняя буква — ошибочные)
 *   "\x78\x70\x65н"              => 'хрен'  (первые 3 буквы — ошибочные)
 *   "вебvfcnth"                  => 'вебмастер'
 *   "webьфыеук"                  => 'webmaster'
 *   "цццюмуыеш.ru"               => 'www.vesti.ru'
 *   "\x54.\x43.\x48\x61вка"      => 'Т.С.Навка'
 *
 * Hints
 *   Типичный пример алгоритма работы для поля ввода с автодополнением:
 *     1. Сделать выборку по исходному запросу;
 *     2. Если есть результат, возвратить его и исходный запрос;
 *     3. Иначе скорректировать исходный запрос через Text_LangCorrect;
 *     4. Если исходный и скорректированный запрос совпадает, возвратить пустой результат и исходный запрос;
 *     5. Иначе сделать выборку по скорректированному запросу;
 *     6. Возвратить результат. Если результат не пустой, возвратить скорректированный запрос, иначе исходный.
 *
 * License
 *   Только для некоммерческого использования!
 *
 * @link     http://code.google.com/p/php-lang-correct/
 * @license  http://creativecommons.org/licenses/by-nc-sa/3.0/
 * @author   Nasibullin Rinat
 * @version  1.4.3
 */
class Text_LangCorrect
{
	/**
	 * Флаг для исправления ошибочно набранных букв в словах,
	 * которые выглядят одинаково в разных раскладках клавиатуры.
	 * Алгоритм работает достаточно надёжно и быстро.
	 */
	const SIMILAR_CHARS = 1;

	/**
	 * Флаг для исправления ошибочно набранных слов в другой раскладке клавиатуры.
	 * Алгоритм может иногда ошибаться, работает в разы медленнее, чем SIMILAR_CHARS.
	 */
	const KEYBOARD_LAYOUT = 2;

	/**
	 * Флаг для добавления исправлений, если влючён флаг KEYBOARD_LAYOUT
	 * Синтаксис и пример: "(,.cn=>бюст)"
	 *                      ^    ^^    ^
	 */
	const ADD_FIX = 4;

	#английский (all)
	private $en = '[a-zA-Z]';
	
	#английский (uppercase)
	private $en_uc = '[A-Z]';

	#английский + символы, которые м.б. набраны по ошибке в английской раскладке клавиатуры вместо русских букв (all)
	private $en_sc = '[a-zA-Z\'`~<>,.:;{}\[\]"]';

	#символы, которые м.б. набраны по ошибке в английской раскладке клавиатуры вместо русских букв
	private $sc = '[\'`~<>,.:;{}\[\]"]';
	private $no_sc = '[^\'`~<>,.:;{}\[\]"]';

	#русский + татарский (all)
	private $tt = '[\xd0-\xd3][\x80-\xbf]
                   (?<=\xd0[\x90-\xbf\x81]|\xd1[\x80-\x8f\x91]|\xd2[\x96\x97\xa2\xa3\xae\xaf\xba\xbb]|\xd3[\x98\x99\xa8\xa9])';

	#русский + татарский (uppercase)
	private $tt_uc = '[\xd0\xd2\xd3][\x81-\xba]
                      (?<=\xd0[\x90-\xaf\x81]|\xd2[\x96\xa2\xae\xba]|\xd3[\x98\xa8])';

	#русский + татарский (для фильтрованных текстов) (all)
	private $tt_f = '[\xd0-\xd3][\x80-\xbf]
                     #комментируем для увеличения скорости, т.к. остальные символы отфильтрованы
                     #(?<=\xd0[\x90-\xbf\x81]|\xd1[\x80-\x8f\x91]|\xd2[\x96\x97\xa2\xa3\xae\xaf\xba\xbb]|\xd3[\x98\x99\xa8\xa9])
                     ';

	#гласная (vowel) (lowercase)
	private $vowel_lc = array(
		'tt' => '\xd0[\xb0\xb5\xb8\xbe]|\xd1[\x83\x8b\x8d\x8e\x8f\x91]  #аеиоуыэюяё (гласные, 10 шт.)
                #| \xd0[\x90\x95\x98\x9e\xa3\xab\xad\xae\xaf\x81]       #АЕИОУЫЭЮЯЁ (гласные, 10 шт.)
                ',
		'en' => '[aeiouy]', #латинских 6 шт.
	);

	#согласная (consonant) + графические знаки для русского языка (ъ, ь) (lowercase)
	private $consonant_lc = array(
		'tt' => '\xd0[\xb1-\xb4\xb6\xb7\xb9\xba-\xbd\xbf]|\xd1[\x80\x81\x82\x84-\x89\x8a\x8c]  #бвгджзйклмнпрстфхцчшщ ъь (согласные, 21+2 шт.)
                #| \xd0[\x91-\x94\x96\x97\x99\x9a-\x9d\x9f-\xa2\xa4-\xa9\xaa\xac]              #БВГДЖЗЙКЛМНПРСТФХЦЧШЩ ЪЬ (согласные, 21+2 шт.)
                ',
		'en' => '[bcdfghjklmnpqrstvwxz]', #латинских 20 шт.
	);

	private $words_exceptions = array(
		'tt' => array(
			'трлн' => null,
			'ющенко' => null,
			'мебельград' => null,
			'дэнис' => null,
		),
		'en' => array(
			'heuer' => null,
		),
	);

	#русские буквы, похожие на англ. (uppercase)
	private $ru_similar_uc = "\xd0[\x90\x92\x95\x9a\x9c\x9d\x9e\xa0-\xa3\xa5]";

	#русские буквы, похожие на англ. (all)
	private $ru_similar = "\xd0[\x90\x92\x95\x9a\x9c\x9d\x9e\xa0-\xa3\xa5\xb0\xb5\xbe]|\xd1[\x80\x81\x83\x85]";

	#англ. буквы, похожие на русские (uppercase)
	private $en_similar_uc = '[ABEKMHOPCTYX]';

	/*
    #$tt_fake = '\xd0[\xb0\xb5\xbe\x90\x92\x95\x9a\x9c\x9d\x9e\xa0\xa1\xa2\xa3\xa5]|\xd1[\x80\x81\x83\x85]';
    $tt_fake = '[\xd0\xd1][\x80-\xbe]
                (?<=\xd0[\xb0\xb5\xbe\x90\x92\x95\x9a\x9c\x9d\x9e\xa0\xa1\xa2\xa3\xa5]|\xd1[\x80\x81\x83\x85])';
    $en_fake = '[aeopcyxABEKMHOPCTYX]';
	*/

	#уникальные русские буквы
	/*
    CASE_UPPER, case_lower
    "\xd0\x81", "\xd1\x91", #Ё ё
    "\xd0\x91", "\xd0\xb1", #Б б
    "\xd0\x92", "\xd0\xb2", #В в
    "\xd0\x93", "\xd0\xb3", #Г г
    "\xd0\x94", "\xd0\xb4", #Д д
    "\xd0\x96", "\xd0\xb6", #Ж ж
    "\xd0\x97", "\xd0\xb7", #З з
    "\xd0\x98", "\xd0\xb8", #И и
    "\xd0\x99", "\xd0\xb9", #Й й
                "\xd0\xba", #К к
    "\xd0\x9b", "\xd0\xbb", #Л л
                "\xd0\xbd", #Н н
    "\xd0\x9f", "\xd0\xbf", #П п
                "\xd1\x82", #Т т
    "\xd0\xa4", "\xd1\x84", #Ф ф
    "\xd0\xa6", "\xd1\x86", #Ц ц
    "\xd0\xa7", "\xd1\x87", #Ч ч
    "\xd0\xa8", "\xd1\x88", #Ш ш
    "\xd0\xa9", "\xd1\x89", #Щ щ
    "\xd0\xaa", "\xd1\x8a", #Ъ ъ
    "\xd0\xab", "\xd1\x8b", #Ы ы
    "\xd0\xac", "\xd1\x8c", #Ь ь
    "\xd0\xad", "\xd1\x8d", #Э э
    "\xd0\xae", "\xd1\x8e", #Ю ю
    "\xd0\xaf", "\xd1\x8f", #Я я
	*/
	#$tt_uniq = "\xd0[\xb1-\xb4\xb6-\xbb\xbd\xbf\x81\x91-\x94\x96-\x99\x9b\x9f\xa4\xa6-\xaf]|\xd1[\x82\x84\x86-\x8f\x91]";
	private $tt_uniq = "[\xd0\xd1][\x82-\xbf]
                        (?<=\xd0[\xb1-\xb4\xb6-\xbb\xbd\xbf\x81\x91-\x94\x96-\x99\x9b\x9f\xa4\xa6-\xaf]|\xd1[\x82\x84\x86-\x8f\x91])";

	#уникальные латинские буквы
	/*
    CASE_UPPER, case_lower
    "\x42", "\x62", #B b
    "\x44", "\x64", #D d
    "\x46", "\x66", #F f
            "\x68", #H h
    "\x49", "\x69", #I i
    "\x4a", "\x6a", #J j
            "\x6b", #K k
    "\x4c", "\x6c", #L l
            "\x6d", #M m
    "\x4e", "\x6e", #N n
    "\x51", "\x71", #Q q
    "\x52", "\x72", #R r
    "\x53", "\x73", #S s
            "\x74", #T t
    "\x55", "\x75", #U u
    "\x56", "\x76", #V v
    "\x57", "\x77", #W w
    "\x5a", "\x7a", #Z z
	*/
	private $en_uniq = "[\x42\x44\x46\x49\x4a\x4c\x4e\x51\x52\x53\x55\x57\x56\x5a\x62\x64\x66\x68\x69\x6a-\x6e\x71-\x77\x7a]";

	private $table_flip; #array
	private $words;      #corrected words
	private $en_correct; #string
	private $tt_correct; #string
	private $mode; #bool

	private $is_flip = false;
	private $method = 0;

	private $table = array(
		#метод 0: таблица исправления ошибочно набранных букв, которые выглядят одинаково (русский <--> английский)
		0 => array(
			#lowercase          #UPPERCASE
			"\xd0\xb0" => 'a',  "\xd0\x90" => 'A',
			"\xd0\x92" => 'B',
			"\xd0\xb5" => 'e',  "\xd0\x95" => 'E',
			"\xd0\x9a" => 'K',
			"\xd0\x9c" => 'M',
			"\xd0\x9d" => 'H',
			"\xd0\xbe" => 'o',  "\xd0\x9e" => 'O',
			"\xd1\x80" => 'p',  "\xd0\xa0" => 'P',
			"\xd1\x81" => 'c',  "\xd0\xa1" => 'C',
			"\xd0\xa2" => 'T',
			"\xd1\x83" => 'y',  "\xd0\xa3" => 'Y',
			"\xd1\x85" => 'x',  "\xd0\xa5" => 'X',
		),
		#метод 1: таблица исправления ошибочно набранных букв в другой раскладке клавиатуры (русский <--> английский)
		1 => array(
			#CASE_UPPER         #case_lower
			"\xd0\x81" => '~',  "\xd1\x91" => '`', #Ё ё
			"\xd0\x90" => 'F',  "\xd0\xb0" => 'f', #А а
			"\xd0\x91" => '<',  "\xd0\xb1" => ',', #Б б
			"\xd0\x92" => 'D',  "\xd0\xb2" => 'd', #В в
			"\xd0\x93" => 'U',  "\xd0\xb3" => 'u', #Г г
			"\xd0\x94" => 'L',  "\xd0\xb4" => 'l', #Д д
			"\xd0\x95" => 'T',  "\xd0\xb5" => 't', #Е е
			"\xd0\x96" => ':',  "\xd0\xb6" => ';', #Ж ж
			"\xd0\x97" => 'P',  "\xd0\xb7" => 'p', #З з
			"\xd0\x98" => 'B',  "\xd0\xb8" => 'b', #И и
			"\xd0\x99" => 'Q',  "\xd0\xb9" => 'q', #Й й
			"\xd0\x9a" => 'R',  "\xd0\xba" => 'r', #К к
			"\xd0\x9b" => 'K',  "\xd0\xbb" => 'k', #Л л
			"\xd0\x9c" => 'V',  "\xd0\xbc" => 'v', #М м
			"\xd0\x9d" => 'Y',  "\xd0\xbd" => 'y', #Н н
			"\xd0\x9e" => 'J',  "\xd0\xbe" => 'j', #О о
			"\xd0\x9f" => 'G',  "\xd0\xbf" => 'g', #П п
			#CASE_UPPER         #case_lower
			"\xd0\xa0" => 'H',  "\xd1\x80" => 'h', #Р р
			"\xd0\xa1" => 'C',  "\xd1\x81" => 'c', #С с
			"\xd0\xa2" => 'N',  "\xd1\x82" => 'n', #Т т
			"\xd0\xa3" => 'E',  "\xd1\x83" => 'e', #У у
			"\xd0\xa4" => 'A',  "\xd1\x84" => 'a', #Ф ф
			"\xd0\xa5" => '{',  "\xd1\x85" => '[', #Х х
			"\xd0\xa6" => 'W',  "\xd1\x86" => 'w', #Ц ц
			"\xd0\xa7" => 'X',  "\xd1\x87" => 'x', #Ч ч
			"\xd0\xa8" => 'I',  "\xd1\x88" => 'i', #Ш ш
			"\xd0\xa9" => 'O',  "\xd1\x89" => 'o', #Щ щ
			"\xd0\xaa" => '}',  "\xd1\x8a" => ']', #Ъ ъ
			"\xd0\xab" => 'S',  "\xd1\x8b" => 's', #Ы ы
			"\xd0\xac" => 'M',  "\xd1\x8c" => 'm', #Ь ь
			"\xd0\xad" => '"',  "\xd1\x8d" => "'", #Э э
			"\xd0\xae" => '>',  "\xd1\x8e" => '.', #Ю ю
			"\xd0\xaf" => 'Z',  "\xd1\x8f" => 'z', #Я я
		),
	);

	#несуществующие N-граммы для гласных букв
	private $vowels3_lc = array(
		'en' => array(
			'aea' => 0,
			'aei' => 1,
			'aeo' => 2,
			'aeu' => 3,
			'aia' => 4,
			'aie' => 5,
			'aii' => 6,
			'aoi' => 7,
			'aou' => 8,
			'aue' => 9,
			'aya' => 10,
			'aye' => 11,
			'ayi' => 12,
			'ayo' => 13,
			'ayu' => 14,
			'eae' => 15,
			'eau' => 16,
			'eea' => 17,
			'eei' => 18,
			'eeu' => 19,
			'eia' => 20,
			'eiu' => 21,
			'eoi' => 22,
			'eou' => 23,
			'eya' => 24,
			'eye' => 25,
			'eyi' => 26,
			'eyo' => 27,
			'iae' => 28,
			'iai' => 29,
			'iao' => 30,
			'iau' => 31,
			'iei' => 32,
			'ieu' => 33,
			'ioa' => 34,
			'ioe' => 35,
			'iou' => 36,
			'iya' => 37,
			'oae' => 38,
			'oea' => 39,
			'oei' => 40,
			'oeo' => 41,
			'oeu' => 42,
			'oey' => 43,
			'oia' => 44,
			'oie' => 45,
			'ooe' => 46,
			'ooi' => 47,
			'oou' => 48,
			'oua' => 49,
			'oue' => 50,
			'oui' => 51,
			'oya' => 52,
			'oye' => 53,
			'oyi' => 54,
			'oyo' => 55,
			'uae' => 56,
			'uai' => 57,
			'uay' => 58,
			'uea' => 59,
			'uee' => 60,
			'uei' => 61,
			'ueo' => 62,
			'ueu' => 63,
			'uey' => 64,
			'uia' => 65,
			'uie' => 66,
			'uio' => 67,
			'uiu' => 68,
			'uoa' => 69,
			'uoi' => 70,
			'uou' => 71,
			'uoy' => 72,
			'uya' => 73,
			'uye' => 74,
			'uyi' => 75,
			'yae' => 76,
			'yao' => 77,
			'yau' => 78,
			'yea' => 79,
			'yei' => 80,
			'yeo' => 81,
			'yey' => 82,
			'yie' => 83,
			'yoi' => 84,
			'you' => 85,
			'yoy' => 86,
			'yua' => 87,
		),
		'tt' => array(
			'аау' => 0,
			'аео' => 1,
			'аеу' => 2,
			'аиа' => 3,
			'аио' => 4,
			'аиу' => 5,
			'аои' => 6,
			'ауэ' => 7,
			'аяя' => 8,
			'еаэ' => 9,
			'еее' => 10,
			'еео' => 11,
			'еоа' => 12,
			'еои' => 13,
			'еоо' => 14,
			'еую' => 15,
			'еуя' => 16,
			'еуё' => 17,
			'иау' => 18,
			'иео' => 19,
			'иие' => 20,
			'иоа' => 21,
			'иои' => 22,
			'иоу' => 23,
			'иоэ' => 24,
			'ияе' => 25,
			'ияи' => 26,
			'ияю' => 27,
			'оаэ' => 28,
			'оео' => 29,
			'оею' => 30,
			'оие' => 31,
			'оуе' => 32,
			'оуя' => 33,
			'оюе' => 34,
			'оюю' => 35,
			'ояе' => 36,
			'уео' => 37,
			'уюю' => 38,
		),
	);

	#несуществующие N-граммы для согласных букв
	private $consonants4_lc = array(
		'en' => array(
			'bldg' => 0,
			'blvd' => 1,
			'bscr' => 2,
			'bstr' => 3,
			'cbcm' => 4,
			'cbft' => 5,
			'chfr' => 6,
			'chmn' => 7,
			'chsc' => 8,
			'chsh' => 9,
			'chst' => 10,
			'chth' => 11,
			'chts' => 12,
			'ckbr' => 13,
			'ckch' => 14,
			'ckcl' => 15,
			'ckdr' => 16,
			'ckgr' => 17,
			'cksc' => 18,
			'cksf' => 19,
			'cksh' => 20,
			'cksk' => 21,
			'cksl' => 22,
			'cksm' => 23,
			'cksn' => 24,
			'cksp' => 25,
			'ckst' => 26,
			'cksw' => 27,
			'ckth' => 28,
			'cktr' => 29,
			'ckwh' => 30,
			'cmps' => 31,
			'dspr' => 32,
			'dstr' => 33,
			'dthw' => 34,
			'ffsc' => 35,
			'ffsh' => 36,
			'ffsp' => 37,
			'fthl' => 38,
			'ftsm' => 39,
			'ftsp' => 40,
			'gdns' => 41,
			'ghbr' => 42,
			'ghfl' => 43,
			'ghsh' => 44,
			'ghtb' => 45,
			'ghtc' => 46,
			'ghtf' => 47,
			'ghth' => 48,
			'ghtj' => 49,
			'ghtl' => 50,
			'ghtm' => 51,
			'ghtn' => 52,
			'ghtr' => 53,
			'ghts' => 54,
			'ghtw' => 55,
			'hdbk' => 56,
			'hnst' => 57,
			'jctn' => 58,
			'khsh' => 59,
			'khst' => 60,
			'lchr' => 61,
			'ldpr' => 62,
			'ldsh' => 63,
			'ldsm' => 64,
			'ldsp' => 65,
			'ldst' => 66,
			'lfsk' => 67,
			'lfth' => 68,
			'lgth' => 69,
			'llfl' => 70,
			'llfr' => 71,
			'llph' => 72,
			'llpl' => 73,
			'llsh' => 74,
			'llsp' => 75,
			'llst' => 76,
			'lltr' => 77,
			'llwr' => 78,
			'lmcr' => 79,
			'lmsm' => 80,
			'lnrk' => 81,
			'lnsh' => 82,
			'lptr' => 83,
			'lsgr' => 84,
			'lshm' => 85,
			'lshw' => 86,
			'lstr' => 87,
			'lthf' => 88,
			'ltsf' => 89,
			'ltsh' => 90,
			'ltst' => 91,
			'mbsc' => 92,
			'mbsh' => 93,
			'mbsk' => 94,
			'mbst' => 95,
			'mddx' => 96,
			'mdnt' => 97,
			'mpbl' => 98,
			'mpgr' => 99,
			'mphl' => 100,
			'mphr' => 101,
			'mpsh' => 102,
			'mpst' => 103,
			'mptl' => 104,
			'mptn' => 105,
			'mptr' => 106,
			'mpts' => 107,
			'mscr' => 108,
			'mstr' => 109,
			'nchb' => 110,
			'nchl' => 111,
			'nchm' => 112,
			'nchn' => 113,
			'nchp' => 114,
			'nchr' => 115,
			'nchw' => 116,
			'nctl' => 117,
			'nctn' => 118,
			'ndbk' => 119,
			'ndbr' => 120,
			'ndch' => 121,
			'ndfl' => 122,
			'ndgl' => 123,
			'ndgr' => 124,
			'ndsc' => 125,
			'ndsh' => 126,
			'ndsl' => 127,
			'ndsm' => 128,
			'ndsp' => 129,
			'ndst' => 130,
			'ndsw' => 131,
			'ndth' => 132,
			'ndwr' => 133,
			'ngcr' => 134,
			'ngsg' => 135,
			'ngsh' => 136,
			'ngsm' => 137,
			'ngsp' => 138,
			'ngst' => 139,
			'ngth' => 140,
			'ngtz' => 141,
			'nksg' => 142,
			'nksh' => 143,
			'nksm' => 144,
			'nkst' => 145,
			'nsch' => 146,
			'nscr' => 147,
			'nsgr' => 148,
			'nshr' => 149,
			'nskr' => 150,
			'nspl' => 151,
			'nspr' => 152,
			'nssh' => 153,
			'nstr' => 154,
			'ntbr' => 155,
			'nthl' => 156,
			'nthr' => 157,
			'nths' => 158,
			'ntsh' => 159,
			'ntsm' => 160,
			'phth' => 161,
			'pstr' => 162,
			'pthr' => 163,
			'pths' => 164,
			'ptwr' => 165,
			'rbst' => 166,
			'rchb' => 167,
			'rchd' => 168,
			'rchl' => 169,
			'rchm' => 170,
			'rchn' => 171,
			'rchp' => 172,
			'rchw' => 173,
			'rdsh' => 174,
			'rdsm' => 175,
			'rdst' => 176,
			'rghs' => 177,
			'rkpl' => 178,
			'rksc' => 179,
			'rksh' => 180,
			'rksk' => 181,
			'rksm' => 182,
			'rksp' => 183,
			'rkst' => 184,
			'rldl' => 185,
			'rldw' => 186,
			'rlfr' => 187,
			'rmch' => 188,
			'rmst' => 189,
			'rmth' => 190,
			'rnbl' => 191,
			'rndl' => 192,
			'rnsk' => 193,
			'rnsp' => 194,
			'rnst' => 195,
			'rsch' => 196,
			'rscr' => 197,
			'rshl' => 198,
			'rshn' => 199,
			'rspr' => 200,
			'rstl' => 201,
			'rstr' => 202,
			'rsts' => 203,
			'rstw' => 204,
			'rtbr' => 205,
			'rtch' => 206,
			'rtcr' => 207,
			'rthb' => 208,
			'rthc' => 209,
			'rthd' => 210,
			'rthf' => 211,
			'rthl' => 212,
			'rthm' => 213,
			'rthq' => 214,
			'rthr' => 215,
			'rths' => 216,
			'rthw' => 217,
			'rtsh' => 218,
			'rtsm' => 219,
			'rtsp' => 220,
			'rtsw' => 221,
			'schl' => 222,
			'schm' => 223,
			'schn' => 224,
			'schw' => 225,
			'scrp' => 226,
			'sgmt' => 227,
			'shcl' => 228,
			'shkh' => 229,
			'shpr' => 230,
			'shpt' => 231,
			'shst' => 232,
			'shtr' => 233,
			'shwh' => 234,
			'smth' => 235,
			'ssrs' => 236,
			'ssst' => 237,
			'sstd' => 238,
			'sstr' => 239,
			'stcr' => 240,
			'sthm' => 241,
			'stpl' => 242,
			'stpr' => 243,
			'stsc' => 244,
			'stwr' => 245,
			'tblt' => 246,
			'tchb' => 247,
			'tchc' => 248,
			'tchd' => 249,
			'tchf' => 250,
			'tchl' => 251,
			'tchm' => 252,
			'tchp' => 253,
			'tchw' => 254,
			'thdr' => 255,
			'thsh' => 256,
			'thsk' => 257,
			'thsp' => 258,
			'thst' => 259,
			'tsch' => 260,
			'tspr' => 261,
			'tstr' => 262,
			'tthr' => 263,
			'ttsb' => 264,
			'tzkr' => 265,
			'whsl' => 266,
			'wnbr' => 267,
			'wnpl' => 268,
			'wnsf' => 269,
			'wnsh' => 270,
			'wnsm' => 271,
			'wnsp' => 272,
			'wnst' => 273,
			'wnsw' => 274,
			'wnth' => 275,
			'wntr' => 276,
			'wrnt' => 277,
			'wsfl' => 278,
			'wspr' => 279,
			'wstr' => 280,
			'xthl' => 281,
		),
		'tt' => array(
			'блзд' => 0,
			'бльд' => 1,
			'брьс' => 2,
			'бств' => 3,
			'бстр' => 4,
			'взбл' => 5,
			'взбр' => 6,
			'взгл' => 7,
			'взгр' => 8,
			'вздв' => 9,
			'вздр' => 10,
			'врвг' => 11,
			'врск' => 12,
			'вскл' => 13,
			'вскр' => 14,
			'вспл' => 15,
			'вспр' => 16,
			'вств' => 17,
			'встр' => 18,
			'всхл' => 19,
			'всхр' => 20,
			'втск' => 21,
			'вхск' => 22,
			'грск' => 23,
			'гств' => 24,
			'гтст' => 25,
			'гшпр' => 26,
			'двзд' => 27,
			'джск' => 28,
			'дрст' => 29,
			'дскр' => 30,
			'дств' => 31,
			'дстр' => 32,
			'дтск' => 33,
			'жств' => 34,
			'звзд' => 35,
			'знст' => 36,
			'зтьс' => 37,
			'йздр' => 38,
			'йкбр' => 39,
			'йльн' => 40,
			'йншт' => 41,
			'йпфр' => 42,
			'йств' => 43,
			'йстр' => 44,
			'йтск' => 45,
			'йфст' => 46,
			'йхсв' => 47,
			'йхск' => 48,
			'йхср' => 49,
			'йхст' => 50,
			'кскл' => 51,
			'кскр' => 52,
			'кспл' => 53,
			'кспр' => 54,
			'кств' => 55,
			'кстн' => 56,
			'кстр' => 57,
			'лвст' => 58,
			'лжск' => 59,
			'лльн' => 60,
			'лльс' => 61,
			'лстр' => 62,
			'лсть' => 63,
			'льгв' => 64,
			'льдж' => 65,
			'льдк' => 66,
			'льдм' => 67,
			'льдс' => 68,
			'льдф' => 69,
			'льдц' => 70,
			'льдш' => 71,
			'льдъ' => 72,
			'льдь' => 73,
			'льзк' => 74,
			'льзн' => 75,
			'льзь' => 76,
			'лькл' => 77,
			'лькн' => 78,
			'льпн' => 79,
			'льпт' => 80,
			'льск' => 81,
			'льсн' => 82,
			'льст' => 83,
			'льтк' => 84,
			'льтм' => 85,
			'льтн' => 86,
			'льтп' => 87,
			'льтр' => 88,
			'льтс' => 89,
			'льтт' => 90,
			'льтф' => 91,
			'льфр' => 92,
			'льцг' => 93,
			'льчс' => 94,
			'льшб' => 95,
			'льшк' => 96,
			'льшн' => 97,
			'льшп' => 98,
			'льшф' => 99,
			'льшь' => 100,
			'мбль' => 101,
			'мбрс' => 102,
			'мвзв' => 103,
			'мздр' => 104,
			'мств' => 105,
			'мтск' => 106,
			'нгль' => 107,
			'нгст' => 108,
			'ндгр' => 109,
			'ндск' => 110,
			'ндсп' => 111,
			'ндшп' => 112,
			'ндшт' => 113,
			'нкск' => 114,
			'нктн' => 115,
			'нктс' => 116,
			'нсгр' => 117,
			'нскм' => 118,
			'нскр' => 119,
			'нспл' => 120,
			'нств' => 121,
			'нстк' => 122,
			'нстр' => 123,
			'нтгл' => 124,
			'нтль' => 125,
			'нтрб' => 126,
			'нтрв' => 127,
			'нтрг' => 128,
			'нтрд' => 129,
			'нтрм' => 130,
			'нтрн' => 131,
			'нтрп' => 132,
			'нтрр' => 133,
			'нтрф' => 134,
			'нтск' => 135,
			'нтст' => 136,
			'нфск' => 137,
			'нцкл' => 138,
			'нцпл' => 139,
			'нькн' => 140,
			'ньск' => 141,
			'ньчж' => 142,
			'псск' => 143,
			'пств' => 144,
			'птск' => 145,
			'рбск' => 146,
			'ргпр' => 147,
			'ргск' => 148,
			'ргфл' => 149,
			'рдск' => 150,
			'рдсм' => 151,
			'рдст' => 152,
			'рздр' => 153,
			'рзть' => 154,
			'ркгр' => 155,
			'ркск' => 156,
			'рктн' => 157,
			'рльс' => 158,
			'рмск' => 159,
			'рмтр' => 160,
			'рнск' => 161,
			'рпск' => 162,
			'рсдр' => 163,
			'рсск' => 164,
			'рств' => 165,
			'рстк' => 166,
			'рстн' => 167,
			'рстр' => 168,
			'рстс' => 169,
			'рсть' => 170,
			'ртвл' => 171,
			'ртвр' => 172,
			'ртгр' => 173,
			'рткр' => 174,
			'ртпл' => 175,
			'ртпр' => 176,
			'ртск' => 177,
			'ртсм' => 178,
			'ртшк' => 179,
			'ртьф' => 180,
			'рхзв' => 181,
			'рхпл' => 182,
			'рхпр' => 183,
			'рхсв' => 184,
			'рхск' => 185,
			'рхсм' => 186,
			'рхср' => 187,
			'рхтв' => 188,
			'рхшт' => 189,
			'рщвл' => 190,
			'рьмл' => 191,
			'скск' => 192,
			'спрь' => 193,
			'сспр' => 194,
			'ссср' => 195,
			'сств' => 196,
			'сстр' => 197,
			'ссшп' => 198,
			'ствл' => 199,
			'стрс' => 200,
			'стрш' => 201,
			'стск' => 202,
			'стьб' => 203,
			'стьд' => 204,
			'стьс' => 205,
			'ськн' => 206,
			'сьмн' => 207,
			'тмст' => 208,
			'тпрр' => 209,
			'трст' => 210,
			'тскр' => 211,
			'тств' => 212,
			'тстр' => 213,
			'ттль' => 214,
			'ттск' => 215,
			'тхск' => 216,
			'фств' => 217,
			'фстр' => 218,
			'хств' => 219,
			'хстр' => 220,
			'хткл' => 221,
			'хтск' => 222,
			'хтсм' => 223,
			'цстр' => 224,
		),
	);

	#несуществующие биграммы в начале и конце слов
	private $bigrams = array(
		#ru
		' ёё' => 0,
		' ёа' => 0,
		' ёб' => 0,
		' ёв' => 0,
		' ёг' => 0,
		' ёд' => 0,
		' ёе' => 0,
		' ёз' => 0,
		' ёи' => 0,
		' ёй' => 0,
		' ён' => 0,
		' ёо' => 0,
		' ёп' => 0,
		' ёс' => 0,
		' ёт' => 0,
		' ёу' => 0,
		' ёф' => 0,
		' ёц' => 0,
		' ёч' => 0,
		' ёщ' => 0,
		' ёъ' => 0,
		' ёы' => 0,
		' ёь' => 0,
		' ёэ' => 0,
		' ёю' => 0,
		' ёя' => 0,
		' аё' => 0,
		' аа' => 0,
		' ае' => 0,
		' ач' => 0,
		' аъ' => 0,
		' аы' => 0,
		' аь' => 0,
		' аю' => 0,
		' ая' => 0,
		' бб' => 0,
		' бв' => 0,
		' бг' => 0,
		' бж' => 0,
		' бй' => 0,
		' бк' => 0,
		' бм' => 0,
		' бн' => 0,
		' бп' => 0,
		' бс' => 0,
		' бт' => 0,
		' бф' => 0,
		' бх' => 0,
		' бц' => 0,
		' бч' => 0,
		' бш' => 0,
		' бщ' => 0,
		' бъ' => 0,
		' вй' => 0,
		' вф' => 0,
		' вщ' => 0,
		' вэ' => 0,
		' вю' => 0,
		' гё' => 0,
		' гб' => 0,
		' гз' => 0,
		' гй' => 0,
		' гк' => 0,
		' гп' => 0,
		' гс' => 0,
		' гт' => 0,
		' гф' => 0,
		' гх' => 0,
		' гц' => 0,
		' гч' => 0,
		' гш' => 0,
		' гщ' => 0,
		' гъ' => 0,
		' гь' => 0,
		' гэ' => 0,
		' дб' => 0,
		' дг' => 0,
		' дд' => 0,
		' дй' => 0,
		' дк' => 0,
		' дп' => 0,
		' дс' => 0,
		' дт' => 0,
		' дф' => 0,
		' дх' => 0,
		' дц' => 0,
		' дч' => 0,
		' дш' => 0,
		' дъ' => 0,
		' дэ' => 0,
		' еа' => 0,
		' еб' => 0,
		' еи' => 0,
		' ео' => 0,
		' ет' => 0,
		' еу' => 0,
		' ец' => 0,
		#' еш' => 0,
		' еъ' => 0,
		' еы' => 0,
		' еь' => 0,
		' еэ' => 0,
		' ея' => 0,
		' жз' => 0,
		' жй' => 0,
		' жк' => 0,
		' жл' => 0,
		' жп' => 0,
		' жс' => 0,
		' жт' => 0,
		' жф' => 0,
		' жх' => 0,
		' жц' => 0,
		' жч' => 0,
		' жш' => 0,
		' жщ' => 0,
		' жъ' => 0,
		' жы' => 0,
		' жь' => 0,
		' жэ' => 0,
		#' жю' => 0,
		' жя' => 0,
		' зб' => 0,
		' зж' => 0,
		' зз' => 0,
		' зй' => 0,
		' зк' => 0,
		' зп' => 0,
		' зс' => 0,
		' зт' => 0,
		' зф' => 0,
		' зх' => 0,
		' зц' => 0,
		' зч' => 0,
		' зш' => 0,
		' зщ' => 0,
		' зъ' => 0,
		' зь' => 0,
		' зэ' => 0,
		' иё' => 0,
		' иа' => 0,
		' иф' => 0,
		' иц' => 0,
		' иъ' => 0,
		' иы' => 0,
		' иь' => 0,
		' иэ' => 0,
		' ия' => 0,
		' йё' => 0,
		' йа' => 0,
		' йб' => 0,
		' йв' => 0,
		' йг' => 0,
		' йд' => 0,
		' йж' => 0,
		' йз' => 0,
		' йи' => 0,
		' йй' => 0,
		' йк' => 0,
		' йл' => 0,
		' йм' => 0,
		' йн' => 0,
		' йп' => 0,
		' йр' => 0,
		' йс' => 0,
		' йт' => 0,
		' йу' => 0,
		' йф' => 0,
		' йх' => 0,
		' йц' => 0,
		' йч' => 0,
		' йш' => 0,
		' йщ' => 0,
		' йъ' => 0,
		' йы' => 0,
		' йь' => 0,
		' йэ' => 0,
		' йю' => 0,
		' йя' => 0,
		' кё' => 0,
		' кб' => 0,
		' кд' => 0,
		' кж' => 0,
		' кй' => 0,
		' кк' => 0,
		' кф' => 0,
		' кц' => 0,
		' кч' => 0,
		' кщ' => 0,
		' къ' => 0,
		' кя' => 0,
		' лв' => 0,
		' лд' => 0,
		' лз' => 0,
		' лй' => 0,
		' лк' => 0,
		' лл' => 0,
		' лм' => 0,
		' лн' => 0,
		' лп' => 0,
		' лр' => 0,
		' лс' => 0,
		' лт' => 0,
		' лф' => 0,
		' лх' => 0,
		' лц' => 0,
		' лч' => 0,
		' лш' => 0,
		' лщ' => 0,
		' лъ' => 0,
		' лэ' => 0,
		' мб' => 0,
		' мв' => 0,
		' мд' => 0,
		' мж' => 0,
		' мй' => 0,
		' мк' => 0,
		' мп' => 0,
		' мт' => 0,
		' мф' => 0,
		' мц' => 0,
		' мъ' => 0,
		' мь' => 0,
		' нб' => 0,
		' нв' => 0,
		' нг' => 0,
		' нд' => 0,
		' нж' => 0,
		' нз' => 0,
		' нй' => 0,
		' нк' => 0,
		' нл' => 0,
		' нм' => 0,
		' нн' => 0,
		' нп' => 0,
		' нс' => 0,
		' нт' => 0,
		' нф' => 0,
		' нх' => 0,
		' нц' => 0,
		' нч' => 0,
		' нш' => 0,
		' нщ' => 0,
		' нъ' => 0,
		' оё' => 0,
		' ои' => 0,
		' оу' => 0,
		' оъ' => 0,
		' оы' => 0,
		' оь' => 0,
		' оэ' => 0,
		' оя' => 0,
		' пб' => 0,
		' пв' => 0,
		' пг' => 0,
		' пд' => 0,
		' пж' => 0,
		' пз' => 0,
		' пй' => 0,
		' пк' => 0,
		' пм' => 0,
		' пп' => 0,
		' пц' => 0,
		' пщ' => 0,
		' пъ' => 0,
		' рб' => 0,
		' рг' => 0,
		' рз' => 0,
		' рй' => 0,
		' рк' => 0,
		' рл' => 0,
		' рм' => 0,
		' рн' => 0,
		' рп' => 0,
		' рр' => 0,
		' рф' => 0,
		' рх' => 0,
		' рч' => 0,
		' рш' => 0,
		' рщ' => 0,
		' ръ' => 0,
		' сй' => 0,
		' сщ' => 0,
		' тб' => 0,
		' тг' => 0,
		' тд' => 0,
		' тж' => 0,
		' тз' => 0,
		' тй' => 0,
		' тн' => 0,
		' тт' => 0,
		' тх' => 0,
		' тц' => 0,
		' тч' => 0,
		' тш' => 0,
		' тъ' => 0,
		' уу' => 0,
		' уъ' => 0,
		' уы' => 0,
		' уь' => 0,
		' фб' => 0,
		' фв' => 0,
		' фг' => 0,
		' фд' => 0,
		' фж' => 0,
		' фз' => 0,
		' фй' => 0,
		' фк' => 0,
		' фм' => 0,
		' фн' => 0,
		' фп' => 0,
		' фс' => 0,
		' фх' => 0,
		' фц' => 0,
		' фч' => 0,
		' фш' => 0,
		' фщ' => 0,
		' фъ' => 0,
		' фэ' => 0,
		' фя' => 0,
		' хё' => 0,
		' хб' => 0,
		' хг' => 0,
		' хд' => 0,
		' хж' => 0,
		' хз' => 0,
		' хй' => 0,
		' хк' => 0,
		' хп' => 0,
		' хс' => 0,
		' хт' => 0,
		' хф' => 0,
		' хц' => 0,
		' хч' => 0,
		' хш' => 0,
		' хщ' => 0,
		' хъ' => 0,
		' хы' => 0,
		' хь' => 0,
		#' хэ' => 0,
		' хю' => 0,
		' хя' => 0,
		' цё' => 0,
		' цб' => 0,
		' цг' => 0,
		' цд' => 0,
		' цж' => 0,
		' цй' => 0,
		' цл' => 0,
		' цм' => 0,
		' цн' => 0,
		' цп' => 0,
		' цр' => 0,
		' цс' => 0,
		' цт' => 0,
		' цф' => 0,
		' цх' => 0,
		' цц' => 0,
		' цч' => 0,
		' цш' => 0,
		' цщ' => 0,
		' цъ' => 0,
		' ць' => 0,
		' цэ' => 0,
		' цю' => 0,
		' ця' => 0,
		' чб' => 0,
		' чг' => 0,
		' чд' => 0,
		' чж' => 0,
		' чз' => 0,
		' чй' => 0,
		' чн' => 0,
		' чп' => 0,
		' чс' => 0,
		' чф' => 0,
		' чц' => 0,
		' чч' => 0,
		' чщ' => 0,
		' чъ' => 0,
		' чы' => 0,
		' чэ' => 0,
		' чю' => 0,
		' чя' => 0,
		' шб' => 0,
		' шг' => 0,
		' шд' => 0,
		' шж' => 0,
		' шз' => 0,
		' шй' => 0,
		' шс' => 0,
		' шф' => 0,
		' шц' => 0,
		' шч' => 0,
		' шщ' => 0,
		' шъ' => 0,
		' шы' => 0,
		' шэ' => 0,
		' шю' => 0,
		' шя' => 0,
		' щб' => 0,
		' щв' => 0,
		' щг' => 0,
		' щд' => 0,
		' щж' => 0,
		' щз' => 0,
		' щй' => 0,
		' щк' => 0,
		' щл' => 0,
		' щм' => 0,
		' щн' => 0,
		' що' => 0,
		' щп' => 0,
		' щр' => 0,
		' щс' => 0,
		' щт' => 0,
		' щф' => 0,
		' щх' => 0,
		' щц' => 0,
		' щч' => 0,
		' щш' => 0,
		' щщ' => 0,
		' щъ' => 0,
		' щы' => 0,
		' щь' => 0,
		' щэ' => 0,
		' щю' => 0,
		' щя' => 0,
		' ъё' => 0,
		' ъа' => 0,
		' ъб' => 0,
		' ъв' => 0,
		' ъг' => 0,
		' ъд' => 0,
		' ъе' => 0,
		' ъж' => 0,
		' ъз' => 0,
		' ъи' => 0,
		' ъй' => 0,
		' ък' => 0,
		' ъл' => 0,
		' ъм' => 0,
		' ън' => 0,
		' ъо' => 0,
		' ъп' => 0,
		' ър' => 0,
		' ъс' => 0,
		' ът' => 0,
		' ъу' => 0,
		' ъф' => 0,
		' ъх' => 0,
		' ъц' => 0,
		' ъч' => 0,
		' ъш' => 0,
		' ъщ' => 0,
		' ъъ' => 0,
		' ъы' => 0,
		' ъь' => 0,
		' ъэ' => 0,
		' ъю' => 0,
		' ъя' => 0,
		' ыё' => 0,
		' ыа' => 0,
		' ыб' => 0,
		' ыв' => 0,
		' ыг' => 0,
		' ыд' => 0,
		' ые' => 0,
		' ыж' => 0,
		' ыз' => 0,
		' ыи' => 0,
		' ый' => 0,
		' ык' => 0,
		' ыл' => 0,
		' ын' => 0,
		' ыо' => 0,
		' ып' => 0,
		' ыр' => 0,
		' ыс' => 0,
		' ыт' => 0,
		' ыу' => 0,
		' ыф' => 0,
		' ых' => 0,
		' ыц' => 0,
		' ыч' => 0,
		' ыш' => 0,
		' ыщ' => 0,
		' ыъ' => 0,
		' ыы' => 0,
		' ыь' => 0,
		' ыэ' => 0,
		' ыю' => 0,
		' ыя' => 0,
		' ьё' => 0,
		' ьа' => 0,
		' ьб' => 0,
		' ьв' => 0,
		' ьг' => 0,
		' ьд' => 0,
		' ье' => 0,
		' ьж' => 0,
		' ьз' => 0,
		' ьи' => 0,
		' ьй' => 0,
		' ьк' => 0,
		' ьл' => 0,
		' ьм' => 0,
		' ьн' => 0,
		' ьо' => 0,
		' ьп' => 0,
		' ьр' => 0,
		' ьс' => 0,
		' ьт' => 0,
		' ьу' => 0,
		' ьф' => 0,
		' ьх' => 0,
		' ьц' => 0,
		' ьч' => 0,
		' ьш' => 0,
		' ьщ' => 0,
		' ьъ' => 0,
		' ьы' => 0,
		' ьь' => 0,
		' ьэ' => 0,
		' ью' => 0,
		' ья' => 0,
		' эё' => 0,
		' эа' => 0,
		' эе' => 0,
		' эи' => 0,
		' эц' => 0,
		' эч' => 0,
		' эщ' => 0,
		' эъ' => 0,
		' эы' => 0,
		' эь' => 0,
		' ээ' => 0,
		' эю' => 0,
		' юё' => 0,
		' юе' => 0,
		' юи' => 0,
		' юй' => 0,
		' юо' => 0,
		' юу' => 0,
		' юц' => 0,
		' юш' => 0,
		' ющ' => 0,
		' юъ' => 0,
		' юы' => 0,
		' юь' => 0,
		' юэ' => 0,
		' юя' => 0,
		' яё' => 0,
		' яа' => 0,
		' яе' => 0,
		' яж' => 0,
		' яо' => 0,
		' яу' => 0,
		' яф' => 0,
		' яц' => 0,
		' яъ' => 0,
		' яы' => 0,
		' яь' => 0,
		' яэ' => 0,
		' яю' => 0,
		' яя' => 0,
		'ёё' => 0,
		'ёё ' => 0,
		'ёа' => 0,
		'ёа ' => 0,
		'ёг ' => 0,
		'ёе' => 0,
		'ёе ' => 0,
		'ёи' => 0,
		'ёи ' => 0,
		'ёй' => 0,
		'ёо' => 0,
		'ёо ' => 0,
		'ёу' => 0,
		'ёу ' => 0,
		'ёф' => 0,
		'ёф ' => 0,
		'ёц ' => 0,
		'ёч ' => 0,
		'ёщ ' => 0,
		'ёъ' => 0,
		'ёъ ' => 0,
		'ёы' => 0,
		'ёы ' => 0,
		'ёь' => 0,
		'ёь ' => 0,
		'ёэ' => 0,
		'ёэ ' => 0,
		'ёю' => 0,
		'ёя' => 0,
		'ёя ' => 0,
		'аё ' => 0,
		'аа ' => 0,
		'аъ' => 0,
		'аъ ' => 0,
		'аы' => 0,
		'аы ' => 0,
		'аь' => 0,
		'аь ' => 0,
		'аэ ' => 0,
		'бё ' => 0,
		'бб ' => 0,
		'бв ' => 0,
		'бг ' => 0,
		'бд ' => 0,
		'бж ' => 0,
		'бз ' => 0,
		'бй' => 0,
		'бй ' => 0,
		'бк ' => 0,
		'бм ' => 0,
		'бн ' => 0,
		'бп ' => 0,
		'бт ' => 0,
		'бф ' => 0,
		'бх ' => 0,
		'бц ' => 0,
		'бч ' => 0,
		'бш ' => 0,
		'бщ ' => 0,
		'бъ ' => 0,
		'бэ ' => 0,
		'вё ' => 0,
		'вб ' => 0,
		'вв ' => 0,
		'вд ' => 0,
		'вж' => 0,
		'вж ' => 0,
		'вз ' => 0,
		'вй' => 0,
		'вй ' => 0,
		'вл ' => 0,
		'вп ' => 0,
		'вф ' => 0,
		'вц ' => 0,
		'вч ' => 0,
		'вщ ' => 0,
		'въ' => 0,
		'въ ' => 0,
		'вэ ' => 0,
		'гё' => 0,
		'гё ' => 0,
		'гб ' => 0,
		'гг ' => 0,
		'гж' => 0,
		'гж ' => 0,
		'гз ' => 0,
		'гй' => 0,
		'гй ' => 0,
		'гк ' => 0,
		'гн ' => 0,
		'гп ' => 0,
		'гф ' => 0,
		'гх' => 0,
		'гх ' => 0,
		'гц' => 0,
		'гц ' => 0,
		'гч ' => 0,
		'гш ' => 0,
		'гщ ' => 0,
		'гъ' => 0,
		'гъ ' => 0,
		'гы ' => 0,
		'гь' => 0,
		'гь ' => 0,
		'гэ ' => 0,
		'гю' => 0,
		'гю ' => 0,
		'гя' => 0,
		'гя ' => 0,
		'дё ' => 0,
		'дб ' => 0,
		'дг ' => 0,
		'дд ' => 0,
		'дй' => 0,
		'дй ' => 0,
		'дк ' => 0,
		'дм ' => 0,
		'дн ' => 0,
		'дп ' => 0,
		'дс ' => 0,
		'дф ' => 0,
		'дх ' => 0,
		'дц ' => 0,
		'дч ' => 0,
		'дш ' => 0,
		'дщ ' => 0,
		'дъ ' => 0,
		'еа ' => 0,
		'еу ' => 0,
		'еъ' => 0,
		'еъ ' => 0,
		'еы' => 0,
		'еы ' => 0,
		'еь' => 0,
		'еь ' => 0,
		'еэ ' => 0,
		'жё ' => 0,
		'жв ' => 0,
		'жг ' => 0,
		'жж ' => 0,
		'жз ' => 0,
		'жй' => 0,
		'жй ' => 0,
		'жк ' => 0,
		'жл ' => 0,
		'жн ' => 0,
		'жп ' => 0,
		'жр ' => 0,
		'жс ' => 0,
		'жт ' => 0,
		'жф ' => 0,
		'жх ' => 0,
		'жц ' => 0,
		'жч ' => 0,
		'жш' => 0,
		'жш ' => 0,
		'жщ' => 0,
		'жщ ' => 0,
		'жъ' => 0,
		'жъ ' => 0,
		'жы ' => 0,
		'жэ ' => 0,
		'жю' => 0,
		'жю ' => 0,
		'жя' => 0,
		'жя ' => 0,
		'зё ' => 0,
		'зж ' => 0,
		'зз ' => 0,
		'зй' => 0,
		'зй ' => 0,
		'зк ' => 0,
		'зп ' => 0,
		'зр ' => 0,
		'зс ' => 0,
		'зт ' => 0,
		'зф' => 0,
		'зф ' => 0,
		'зх' => 0,
		'зх ' => 0,
		'зц ' => 0,
		'зч ' => 0,
		'зш ' => 0,
		'зщ' => 0,
		'зщ ' => 0,
		'зъ ' => 0,
		'зэ ' => 0,
		'иъ' => 0,
		'иъ ' => 0,
		'иы' => 0,
		'иы ' => 0,
		'иь' => 0,
		'иь ' => 0,
		'иэ ' => 0,
		'йё' => 0,
		'йё ' => 0,
		'йа ' => 0,
		'йв ' => 0,
		'йг ' => 0,
		'йж' => 0,
		'йж ' => 0,
		'йз ' => 0,
		'йи ' => 0,
		'йй' => 0,
		'йй ' => 0,
		'йо ' => 0,
		'йу' => 0,
		'йу ' => 0,
		'йч ' => 0,
		'йш ' => 0,
		'йщ ' => 0,
		'йъ' => 0,
		'йъ ' => 0,
		'йы' => 0,
		'йы ' => 0,
		'йь' => 0,
		'йь ' => 0,
		'йэ' => 0,
		'йэ ' => 0,
		'йю' => 0,
		'йю ' => 0,
		'йя' => 0,
		'кё ' => 0,
		'кб ' => 0,
		'кг ' => 0,
		'кд ' => 0,
		'кж ' => 0,
		'кз ' => 0,
		'кй' => 0,
		'кй ' => 0,
		'км ' => 0,
		'кн ' => 0,
		'кф ' => 0,
		'кц ' => 0,
		'кч ' => 0,
		'кш ' => 0,
		'кщ' => 0,
		'кщ ' => 0,
		'къ' => 0,
		'къ ' => 0,
		'кы ' => 0,
		'кь ' => 0,
		'кэ' => 0,
		'кэ ' => 0,
		'кя' => 0,
		'кя ' => 0,
		'лв ' => 0,
		'лж ' => 0,
		'лз ' => 0,
		'лй' => 0,
		'лй ' => 0,
		'лр ' => 0,
		'лф ' => 0,
		'лх ' => 0,
		'лц ' => 0,
		'лч ' => 0,
		'лш ' => 0,
		'лщ ' => 0,
		'лъ' => 0,
		'лъ ' => 0,
		'лэ' => 0,
		'лэ ' => 0,
		'мё ' => 0,
		'мв ' => 0,
		'мг ' => 0,
		'мд ' => 0,
		'мз ' => 0,
		'мй' => 0,
		'мк ' => 0,
		'мл ' => 0,
		'мр ' => 0,
		'мх ' => 0,
		'мц ' => 0,
		'мч ' => 0,
		'мш ' => 0,
		'мщ ' => 0,
		'мъ' => 0,
		'мъ ' => 0,
		'мэ ' => 0,
		'мю ' => 0,
		'нё ' => 0,
		'нб ' => 0,
		'нв ' => 0,
		'нй' => 0,
		'нл ' => 0,
		'нп ' => 0,
		'нщ ' => 0,
		'нъ ' => 0,
		'нэ ' => 0,
		'оъ' => 0,
		'оъ ' => 0,
		'оы' => 0,
		'оы ' => 0,
		'оь' => 0,
		'оь ' => 0,
		'пё ' => 0,
		'пб ' => 0,
		'пв' => 0,
		'пв ' => 0,
		'пг' => 0,
		'пг ' => 0,
		'пд ' => 0,
		'пж' => 0,
		'пж ' => 0,
		'пз' => 0,
		'пз ' => 0,
		'пй' => 0,
		'пй ' => 0,
		'пк ' => 0,
		'пл ' => 0,
		'пм ' => 0,
		'пн ' => 0,
		'пф ' => 0,
		'пх ' => 0,
		'пц ' => 0,
		'пч ' => 0,
		'пш ' => 0,
		'пщ ' => 0,
		'пъ' => 0,
		'пъ ' => 0,
		'пэ' => 0,
		'пэ ' => 0,
		'пю ' => 0,
		'рё ' => 0,
		'рй' => 0,
		'рй ' => 0,
		'ръ' => 0,
		'ръ ' => 0,
		'рэ ' => 0,
		'сб ' => 0,
		'св ' => 0,
		'сг ' => 0,
		'сд ' => 0,
		'сж ' => 0,
		'сз' => 0,
		'сз ' => 0,
		'сй' => 0,
		'сй ' => 0,
		'сн ' => 0,
		'сп ' => 0,
		'сф ' => 0,
		'сц ' => 0,
		'сч ' => 0,
		'сш ' => 0,
		'сщ ' => 0,
		'съ ' => 0,
		'сэ ' => 0,
		'тб ' => 0,
		'тг ' => 0,
		'тд ' => 0,
		'тж ' => 0,
		'тз ' => 0,
		'тй' => 0,
		'тй ' => 0,
		'тк ' => 0,
		'тл ' => 0,
		'тп ' => 0,
		'тф ' => 0,
		'тх ' => 0,
		'тц ' => 0,
		'тш ' => 0,
		'тщ ' => 0,
		'тъ ' => 0,
		'уё ' => 0,
		'уо ' => 0,
		'уу ' => 0,
		'уц ' => 0,
		'уъ' => 0,
		'уъ ' => 0,
		'уы' => 0,
		'уы ' => 0,
		'уь' => 0,
		'уь ' => 0,
		'уэ ' => 0,
		'фё ' => 0,
		'фб ' => 0,
		'фв ' => 0,
		'фг ' => 0,
		'фд ' => 0,
		'фж' => 0,
		'фж ' => 0,
		'фз' => 0,
		'фз ' => 0,
		'фй' => 0,
		'фй ' => 0,
		'фк ' => 0,
		'фл ' => 0,
		'фн ' => 0,
		'фп' => 0,
		'фп ' => 0,
		'фс ' => 0,
		'фх' => 0,
		'фх ' => 0,
		'фц' => 0,
		'фц ' => 0,
		'фч ' => 0,
		'фш ' => 0,
		'фщ ' => 0,
		'фъ' => 0,
		'фъ ' => 0,
		'фэ' => 0,
		'фэ ' => 0,
		'фю ' => 0,
		'хё' => 0,
		'хё ' => 0,
		'хб ' => 0,
		'хг ' => 0,
		'хд ' => 0,
		'хж ' => 0,
		'хз ' => 0,
		'хй' => 0,
		'хй ' => 0,
		'хк ' => 0,
		'хн ' => 0,
		'хп ' => 0,
		'хр ' => 0,
		'хс ' => 0,
		'хф ' => 0,
		'хх ' => 0,
		'хц ' => 0,
		'хч ' => 0,
		'хш ' => 0,
		'хщ' => 0,
		'хщ ' => 0,
		'хъ ' => 0,
		'хы' => 0,
		'хы ' => 0,
		'хь' => 0,
		'хь ' => 0,
		'хэ ' => 0,
		'хю' => 0,
		'хю ' => 0,
		'хя' => 0,
		'хя ' => 0,
		'цё' => 0,
		'цё ' => 0,
		'цб' => 0,
		'цб ' => 0,
		'цв ' => 0,
		'цг ' => 0,
		'цд ' => 0,
		'цж' => 0,
		'цж ' => 0,
		'цз ' => 0,
		'цй' => 0,
		'цй ' => 0,
		'цк ' => 0,
		'цл ' => 0,
		'цм ' => 0,
		'цн ' => 0,
		'цп ' => 0,
		'цр ' => 0,
		'цс ' => 0,
		'цт ' => 0,
		'цф' => 0,
		'цф ' => 0,
		'цх' => 0,
		'цх ' => 0,
		'цц ' => 0,
		'цч' => 0,
		'цч ' => 0,
		'цш ' => 0,
		'цщ' => 0,
		'цщ ' => 0,
		'цъ' => 0,
		'цъ ' => 0,
		'ць' => 0,
		'ць ' => 0,
		'цэ' => 0,
		'цэ ' => 0,
		'цю' => 0,
		'цю ' => 0,
		'ця' => 0,
		'ця ' => 0,
		'чё ' => 0,
		'чб ' => 0,
		'чг' => 0,
		'чг ' => 0,
		'чд' => 0,
		'чд ' => 0,
		'чж ' => 0,
		'чз' => 0,
		'чз ' => 0,
		'чй' => 0,
		'чй ' => 0,
		'чк ' => 0,
		'чл ' => 0,
		'чм ' => 0,
		'чн ' => 0,
		'чп' => 0,
		'чп ' => 0,
		'чр ' => 0,
		'чс ' => 0,
		'чф' => 0,
		'чф ' => 0,
		'чх ' => 0,
		'чц ' => 0,
		'чч ' => 0,
		'чш ' => 0,
		'чщ' => 0,
		'чщ ' => 0,
		'чъ' => 0,
		'чъ ' => 0,
		'чы' => 0,
		'чы ' => 0,
		'чэ' => 0,
		'чэ ' => 0,
		'чю' => 0,
		'чю ' => 0,
		'чя' => 0,
		'чя ' => 0,
		'шё ' => 0,
		'шб ' => 0,
		'шг ' => 0,
		'шд' => 0,
		'шд ' => 0,
		'шж' => 0,
		'шж ' => 0,
		'шз' => 0,
		'шз ' => 0,
		'шй' => 0,
		'шй ' => 0,
		'шк ' => 0,
		'шл ' => 0,
		'шм ' => 0,
		'шн ' => 0,
		'шп ' => 0,
		'шр ' => 0,
		'шс ' => 0,
		'шф ' => 0,
		'шх' => 0,
		'шх ' => 0,
		'шч ' => 0,
		'шш' => 0,
		'шш ' => 0,
		'шщ' => 0,
		'шщ ' => 0,
		'шъ' => 0,
		'шъ ' => 0,
		'шы' => 0,
		'шы ' => 0,
		'шэ' => 0,
		'шэ ' => 0,
		'шя' => 0,
		'шя ' => 0,
		'щб' => 0,
		'щб ' => 0,
		'щв ' => 0,
		'щг' => 0,
		'щг ' => 0,
		'щд' => 0,
		'щд ' => 0,
		'щж' => 0,
		'щж ' => 0,
		'щз' => 0,
		'щз ' => 0,
		'щй' => 0,
		'щй ' => 0,
		'щк' => 0,
		'щк ' => 0,
		'щл' => 0,
		'щл ' => 0,
		'щм ' => 0,
		'щн ' => 0,
		'щп' => 0,
		'щп ' => 0,
		'щр ' => 0,
		'щс' => 0,
		'щс ' => 0,
		'щт' => 0,
		'щт ' => 0,
		'щф' => 0,
		'щф ' => 0,
		'щх' => 0,
		'щх ' => 0,
		'щц' => 0,
		'щц ' => 0,
		'щч' => 0,
		'щч ' => 0,
		'щш' => 0,
		'щш ' => 0,
		'щщ' => 0,
		'щщ ' => 0,
		'щъ' => 0,
		'щъ ' => 0,
		'щы' => 0,
		'щы ' => 0,
		'щэ' => 0,
		'щэ ' => 0,
		'щю' => 0,
		'щю ' => 0,
		'щя' => 0,
		'щя ' => 0,
		'ъё ' => 0,
		'ъа' => 0,
		'ъа ' => 0,
		'ъб' => 0,
		'ъб ' => 0,
		'ъв' => 0,
		'ъв ' => 0,
		'ъг' => 0,
		'ъг ' => 0,
		'ъд' => 0,
		'ъд ' => 0,
		'ъе ' => 0,
		'ъж' => 0,
		'ъж ' => 0,
		'ъз' => 0,
		'ъз ' => 0,
		'ъи' => 0,
		'ъи ' => 0,
		'ъй' => 0,
		'ъй ' => 0,
		'ък' => 0,
		'ък ' => 0,
		'ъл' => 0,
		'ъл ' => 0,
		'ъм' => 0,
		'ъм ' => 0,
		'ън' => 0,
		'ън ' => 0,
		'ъо' => 0,
		'ъо ' => 0,
		'ъп' => 0,
		'ъп ' => 0,
		'ър' => 0,
		'ър ' => 0,
		'ъс' => 0,
		'ъс ' => 0,
		'ът' => 0,
		'ът ' => 0,
		'ъу' => 0,
		'ъу ' => 0,
		'ъф' => 0,
		'ъф ' => 0,
		'ъх' => 0,
		'ъх ' => 0,
		'ъц' => 0,
		'ъц ' => 0,
		'ъч' => 0,
		'ъч ' => 0,
		'ъш' => 0,
		'ъш ' => 0,
		'ъщ' => 0,
		'ъщ ' => 0,
		'ъъ' => 0,
		'ъъ ' => 0,
		'ъы' => 0,
		'ъы ' => 0,
		'ъь' => 0,
		'ъь ' => 0,
		'ъэ' => 0,
		'ъэ ' => 0,
		'ъю ' => 0,
		'ъя ' => 0,
		'ыё' => 0,
		'ыё ' => 0,
		'ыа' => 0,
		'ыа ' => 0,
		'ыи ' => 0,
		'ыо ' => 0,
		'ыу ' => 0,
		'ыф ' => 0,
		'ыъ' => 0,
		'ыъ ' => 0,
		'ыы' => 0,
		'ыы ' => 0,
		'ыь' => 0,
		'ыь ' => 0,
		'ыэ' => 0,
		'ыэ ' => 0,
		'ыю ' => 0,
		'ьа' => 0,
		'ьа ' => 0,
		'ьв ' => 0,
		'ьг ' => 0,
		'ьж ' => 0,
		'ьз ' => 0,
		'ьй' => 0,
		'ьй ' => 0,
		'ьл ' => 0,
		'ьн ' => 0,
		'ьр ' => 0,
		'ьу' => 0,
		'ьу ' => 0,
		'ьх ' => 0,
		'ьщ ' => 0,
		'ьъ' => 0,
		'ьъ ' => 0,
		'ьы ' => 0,
		'ьь' => 0,
		'ьь ' => 0,
		'ьэ ' => 0,
		'эё' => 0,
		'эё ' => 0,
		'эа' => 0,
		'эа ' => 0,
		'эб' => 0,
		'эб ' => 0,
		'эв ' => 0,
		'эг ' => 0,
		'эд ' => 0,
		'эе' => 0,
		'эе ' => 0,
		'эж' => 0,
		'эж ' => 0,
		'эз ' => 0,
		'эи ' => 0,
		'эй ' => 0,
		'эл ' => 0,
		'эм ' => 0,
		'эн ' => 0,
		'эо' => 0,
		'эо ' => 0,
		'эу' => 0,
		'эу ' => 0,
		'эф ' => 0,
		'эх ' => 0,
		'эц' => 0,
		'эц ' => 0,
		'эч' => 0,
		'эч ' => 0,
		'эш ' => 0,
		'эщ' => 0,
		'эщ ' => 0,
		'эъ' => 0,
		'эъ ' => 0,
		'эы' => 0,
		'эы ' => 0,
		'эь' => 0,
		'эь ' => 0,
		'ээ ' => 0,
		'эю' => 0,
		'эю ' => 0,
		'эя' => 0,
		'эя ' => 0,
		'юё' => 0,
		'юё ' => 0,
		'юа ' => 0,
		'юе ' => 0,
		'юж ' => 0,
		'юи ' => 0,
		'юл ' => 0,
		'юо ' => 0,
		'юу' => 0,
		'юу ' => 0,
		'юц ' => 0,
		'юъ' => 0,
		'юъ ' => 0,
		'юы' => 0,
		'юы ' => 0,
		'юь' => 0,
		'юь ' => 0,
		'юэ ' => 0,
		'юя' => 0,
		'яё' => 0,
		'яё ' => 0,
		'яа' => 0,
		'яа ' => 0,
		'яе ' => 0,
		'яо ' => 0,
		'яф' => 0,
		'яф ' => 0,
		'яъ' => 0,
		'яъ ' => 0,
		'яы' => 0,
		'яы ' => 0,
		'яь' => 0,
		'яь ' => 0,
		'яэ' => 0,
		'яэ ' => 0,
		#en
		' \'f' => 0,
		' \'p' => 0,
		' \'q' => 0,
		' \'r' => 0,
		' \'x' => 0,
		' \'y' => 0,
		' \'z' => 0,
		' bj' => 0,
		' bq' => 0,
		' bz' => 0,
		' c\'' => 0,
		' cq' => 0,
		' cv' => 0,
		' cx' => 0,
		' dq' => 0,
		' dx' => 0,
		' ez' => 0,
		' f\'' => 0,
		' fh' => 0,
		' fk' => 0,
		' fq' => 0,
		' fv' => 0,
		' fw' => 0,
		' fz' => 0,
		' g\'' => 0,
		' gf' => 0,
		' gg' => 0,
		' gj' => 0,
		' gv' => 0,
		' gx' => 0,
		' gz' => 0,
		' h\'' => 0,
		' hj' => 0,
		' hk' => 0,
		' hn' => 0,
		' hq' => 0,
		' hx' => 0,
		' iq' => 0,
		' iw' => 0,
		' iy' => 0,
		' jb' => 0,
		' jf' => 0,
		' jh' => 0,
		' jj' => 0,
		' jk' => 0,
		' jl' => 0,
		' jm' => 0,
		' jq' => 0,
		' jw' => 0,
		' jx' => 0,
		' jy' => 0,
		' jz' => 0,
		' k\'' => 0,
		' kf' => 0,
		' kj' => 0,
		' kq' => 0,
		' kt' => 0,
		' kx' => 0,
		' kz' => 0,
		' lj' => 0,
		' lk' => 0,
		' lq' => 0,
		' lv' => 0,
		' mj' => 0,
		' mq' => 0,
		' mz' => 0,
		' nj' => 0,
		' nk' => 0,
		' nq' => 0,
		' nz' => 0,
		' oq' => 0,
		' pj' => 0,
		' pz' => 0,
		' qb' => 0,
		' qe' => 0,
		' qf' => 0,
		' qg' => 0,
		' qh' => 0,
		' qj' => 0,
		' qk' => 0,
		' qo' => 0,
		' qp' => 0,
		' qs' => 0,
		' qv' => 0,
		' qx' => 0,
		' qy' => 0,
		' qz' => 0,
		' rb' => 0,
		' rk' => 0,
		' rq' => 0,
		' rv' => 0,
		' rx' => 0,
		' rz' => 0,
		' sz' => 0,
		' tf' => 0,
		' tg' => 0,
		' tj' => 0,
		' tq' => 0,
		' u\'' => 0,
		' ue' => 0,
		' uj' => 0,
		' uo' => 0,
		' uq' => 0,
		' uu' => 0,
		' uy' => 0,
		' vb' => 0,
		' vj' => 0,
		' vk' => 0,
		' vn' => 0,
		' vq' => 0,
		' vr' => 0,
		' vv' => 0,
		' vw' => 0,
		' vx' => 0,
		' vy' => 0,
		' vz' => 0,
		' wj' => 0,
		' wl' => 0,
		' wn' => 0,
		' wq' => 0,
		' wx' => 0,
		' wz' => 0,
		' xb' => 0,
		' xf' => 0,
		' xg' => 0,
		' xh' => 0,
		' xj' => 0,
		' xk' => 0,
		' xq' => 0,
		' xt' => 0,
		' xu' => 0,
		' xz' => 0,
		' yf' => 0,
		' yg' => 0,
		' yh' => 0,
		' yj' => 0,
		' yk' => 0,
		' yl' => 0,
		' yn' => 0,
		' yq' => 0,
		' yv' => 0,
		' yx' => 0,
		' yy' => 0,
		' yz' => 0,
		' z\'' => 0,
		' zb' => 0,
		' zc' => 0,
		' zd' => 0,
		' zf' => 0,
		' zg' => 0,
		' zh' => 0,
		' zj' => 0,
		' zk' => 0,
		' zl' => 0,
		' zm' => 0,
		' zq' => 0,
		' zr' => 0,
		' zv' => 0,
		' zw' => 0,
		' zx' => 0,
		' zz' => 0,
		'\'a ' => 0,
		'\'b' => 0,
		'\'b ' => 0,
		'\'c ' => 0,
		'\'f' => 0,
		'\'f ' => 0,
		'\'g' => 0,
		'\'g ' => 0,
		'\'h ' => 0,
		'\'i ' => 0,
		'\'j' => 0,
		'\'j ' => 0,
		'\'k' => 0,
		'\'k ' => 0,
		'\'l ' => 0,
		'\'n ' => 0,
		'\'o ' => 0,
		'\'p ' => 0,
		'\'q' => 0,
		'\'q ' => 0,
		'\'r ' => 0,
		'\'u' => 0,
		'\'u ' => 0,
		'\'v ' => 0,
		'\'w ' => 0,
		'\'x' => 0,
		'\'x ' => 0,
		'\'z' => 0,
		'\'z ' => 0,
		'b\' ' => 0,
		'bg ' => 0,
		'bh ' => 0,
		'bp ' => 0,
		'bq' => 0,
		'bq ' => 0,
		'bv ' => 0,
		'bx' => 0,
		'bz' => 0,
		'bz ' => 0,
		'c\' ' => 0,
		'cf ' => 0,
		'cj' => 0,
		'cn ' => 0,
		'cq ' => 0,
		'cv' => 0,
		'cw' => 0,
		'cx' => 0,
		'cx ' => 0,
		'cz ' => 0,
		'db ' => 0,
		'dj ' => 0,
		'dk ' => 0,
		'dw ' => 0,
		'dx' => 0,
		'eh ' => 0,
		'ej ' => 0,
		'f\' ' => 0,
		'fg ' => 0,
		'fh ' => 0,
		'fj' => 0,
		'fj ' => 0,
		'fk' => 0,
		'fk ' => 0,
		'fq' => 0,
		'fq ' => 0,
		'fv ' => 0,
		'fw ' => 0,
		'fx' => 0,
		'fx ' => 0,
		'fz' => 0,
		'fz ' => 0,
		'g\' ' => 0,
		'gc ' => 0,
		'gf ' => 0,
		'gj ' => 0,
		'gk ' => 0,
		'gl ' => 0,
		'gq' => 0,
		'gq ' => 0,
		'gv' => 0,
		'gv ' => 0,
		'gw ' => 0,
		'gx' => 0,
		'gx ' => 0,
		'gz ' => 0,
		'hb ' => 0,
		'hc ' => 0,
		'hg ' => 0,
		'hh ' => 0,
		'hj' => 0,
		'hj ' => 0,
		'hk ' => 0,
		'hv' => 0,
		'hv ' => 0,
		'hw ' => 0,
		'hx' => 0,
		'hx ' => 0,
		'hz' => 0,
		'i\' ' => 0,
		'ih ' => 0,
		'iq ' => 0,
		'iw ' => 0,
		'j\'' => 0,
		'j\' ' => 0,
		'jb' => 0,
		'jb ' => 0,
		'jc' => 0,
		'jc ' => 0,
		'jd' => 0,
		'jf' => 0,
		'jg' => 0,
		'jg ' => 0,
		'jh' => 0,
		'jh ' => 0,
		'jj' => 0,
		'jj ' => 0,
		'jk ' => 0,
		'jl ' => 0,
		'jm' => 0,
		'jm ' => 0,
		'jn' => 0,
		'jn ' => 0,
		'jp ' => 0,
		'jq' => 0,
		'jq ' => 0,
		'jr' => 0,
		'jr ' => 0,
		'js' => 0,
		'js ' => 0,
		'jt' => 0,
		'ju ' => 0,
		'jv' => 0,
		'jv ' => 0,
		'jw' => 0,
		'jw ' => 0,
		'jx' => 0,
		'jx ' => 0,
		'jy' => 0,
		'jy ' => 0,
		'jz' => 0,
		'jz ' => 0,
		'kb ' => 0,
		'kc ' => 0,
		'kd ' => 0,
		'kj ' => 0,
		'km ' => 0,
		'kp ' => 0,
		'kq' => 0,
		'kq ' => 0,
		'kv' => 0,
		'kv ' => 0,
		'kx' => 0,
		'kx ' => 0,
		'kz' => 0,
		'kz ' => 0,
		'lg ' => 0,
		'lh ' => 0,
		'lj ' => 0,
		'lq ' => 0,
		'lr ' => 0,
		'lv ' => 0,
		'lw ' => 0,
		'lx' => 0,
		'lz ' => 0,
		'm\' ' => 0,
		'mg ' => 0,
		'mh ' => 0,
		'mj ' => 0,
		'mk ' => 0,
		'mq' => 0,
		'mq ' => 0,
		'mx' => 0,
		'mx ' => 0,
		'mz' => 0,
		'nb ' => 0,
		'nm ' => 0,
		'pj ' => 0,
		'pk ' => 0,
		'pq' => 0,
		'pq ' => 0,
		'pv' => 0,
		'pw ' => 0,
		'px' => 0,
		'px ' => 0,
		'pz ' => 0,
		'q\'' => 0,
		'q\' ' => 0,
		'qa ' => 0,
		'qb' => 0,
		'qb ' => 0,
		'qc' => 0,
		'qc ' => 0,
		'qd' => 0,
		'qd ' => 0,
		'qe' => 0,
		'qe ' => 0,
		'qf' => 0,
		'qf ' => 0,
		'qg' => 0,
		'qg ' => 0,
		'qh' => 0,
		'qh ' => 0,
		'qi' => 0,
		'qj' => 0,
		'qj ' => 0,
		'qk' => 0,
		'qk ' => 0,
		'ql' => 0,
		'ql ' => 0,
		'qm' => 0,
		'qm ' => 0,
		'qn' => 0,
		'qn ' => 0,
		'qo' => 0,
		'qo ' => 0,
		'qp' => 0,
		'qp ' => 0,
		'qq' => 0,
		'qq ' => 0,
		'qr' => 0,
		'qs' => 0,
		'qs ' => 0,
		'qt' => 0,
		'qt ' => 0,
		'qu ' => 0,
		'qv' => 0,
		'qv ' => 0,
		'qw' => 0,
		'qw ' => 0,
		'qx' => 0,
		'qx ' => 0,
		'qy' => 0,
		'qy ' => 0,
		'qz' => 0,
		'qz ' => 0,
		'rq ' => 0,
		'rz ' => 0,
		'sg ' => 0,
		'sj ' => 0,
		'sx' => 0,
		'sx ' => 0,
		'sz' => 0,
		'sz ' => 0,
		'tg ' => 0,
		'tj ' => 0,
		'tq' => 0,
		'tq ' => 0,
		'tx' => 0,
		'tx ' => 0,
		'uj ' => 0,
		'uq ' => 0,
		'uu ' => 0,
		'uw ' => 0,
		'v\' ' => 0,
		'vb' => 0,
		'vb ' => 0,
		'vc' => 0,
		'vf' => 0,
		'vf ' => 0,
		'vg' => 0,
		'vh' => 0,
		'vh ' => 0,
		'vj' => 0,
		'vj ' => 0,
		'vk' => 0,
		'vk ' => 0,
		'vl ' => 0,
		'vm' => 0,
		'vn ' => 0,
		'vp' => 0,
		'vp ' => 0,
		'vq' => 0,
		'vq ' => 0,
		'vr ' => 0,
		'vv ' => 0,
		'vw' => 0,
		'vw ' => 0,
		'vx' => 0,
		'vz' => 0,
		'vz ' => 0,
		'w\' ' => 0,
		'wb ' => 0,
		'wc ' => 0,
		'wf ' => 0,
		'wg ' => 0,
		'wj' => 0,
		'wj ' => 0,
		'wq' => 0,
		'wq ' => 0,
		'wr ' => 0,
		'wv' => 0,
		'wv ' => 0,
		'wx' => 0,
		'wz ' => 0,
		'x\'' => 0,
		'x\' ' => 0,
		'xa ' => 0,
		'xb ' => 0,
		'xc ' => 0,
		'xd' => 0,
		'xd ' => 0,
		'xf ' => 0,
		'xg ' => 0,
		'xh ' => 0,
		'xj' => 0,
		'xj ' => 0,
		'xk' => 0,
		'xk ' => 0,
		'xl ' => 0,
		'xm ' => 0,
		'xn' => 0,
		'xn ' => 0,
		'xp ' => 0,
		'xq ' => 0,
		'xr' => 0,
		'xr ' => 0,
		'xs ' => 0,
		'xu ' => 0,
		'xv' => 0,
		'xv ' => 0,
		'xw ' => 0,
		'xx' => 0,
		'xz' => 0,
		'xz ' => 0,
		'yb ' => 0,
		'yc ' => 0,
		'yd ' => 0,
		'yf ' => 0,
		'yg ' => 0,
		'yh ' => 0,
		'yj ' => 0,
		'yq' => 0,
		'yq ' => 0,
		'yu ' => 0,
		'yv ' => 0,
		'yw ' => 0,
		'yy' => 0,
		'yy ' => 0,
		'yz ' => 0,
		'z\'' => 0,
		'z\' ' => 0,
		'zb ' => 0,
		'zc' => 0,
		'zc ' => 0,
		'zd' => 0,
		'zd ' => 0,
		'zf' => 0,
		'zf ' => 0,
		'zg ' => 0,
		'zh' => 0,
		'zh ' => 0,
		'zj' => 0,
		'zj ' => 0,
		'zk ' => 0,
		'zl ' => 0,
		'zn' => 0,
		'zn ' => 0,
		'zp ' => 0,
		'zq' => 0,
		'zq ' => 0,
		'zr' => 0,
		'zr ' => 0,
		'zs' => 0,
		'zs ' => 0,
		'zt' => 0,
		'zt ' => 0,
		'zu ' => 0,
		'zv ' => 0,
		'zw ' => 0,
		'zx' => 0,
		'zx ' => 0,
	);

	/**
	 *
	 * @param  array|null  $words_exceptions
	 */
	public function __construct(array $words_exceptions = null)
	{
		if (! ReflectionTypeHint::isValid()) return false;
		#русский --> английский:
		$this->en_correct  = '/(?: (?:' . $this->tt_f . ')
                                   (?: (?:' . $this->en_uniq . ') | (?:' . $this->en_sc . '){2} )
                                 | (?:' . $this->en_sc . ')
                                   (?:' . $this->tt_f . ')
                                   (?:' . $this->en_sc . ')
                                 | (?: (?:' . $this->en_uniq . ') | (?:' . $this->en_sc . '){2} )
                                   (?:' . $this->tt_f . ')
                               )
                              /sxSX';
		#английский --> русский:
		$this->tt_correct  = '/(?: (?:' . $this->en_sc . ')
                                   (?: (?:' . $this->tt_uniq . ') | (?:' . $this->tt_f . '){2} )
                                 | (?:' . $this->tt_f . ')
                                   (?:' . $this->en_sc . ')
                                   (?:' . $this->tt_f . ')
                                 | (?: (?:' . $this->tt_uniq . ') | (?:' . $this->tt_f . '){2} )
                                   (?:' . $this->en_sc . ')
                               )
                              /sxSX';
		$this->table_flip = array(
			0 => array_flip($this->table[0]),
			1 => array_flip($this->table[1]),
		);
		if (is_array($words_exceptions)) $this->words_exceptions += $words_exceptions;
	}

	/**
	 * Исправляет клавиатурные опечатки в тексте.
	 * 
	 * @param   scalar|null   $s       Текст в кодировке UTF-8.
	 * @param   int           $mode    Константы self::SIMILAR_CHARS и/или self::KEYBOARD_LAYOUT,
	 *                                 (их можно комбинировать). Описание констант см. выше.
	 *                                 При использовании self::KEYBOARD_LAYOUT время работы увеличивается примерно в 10 раз.
	 * @param   array         &$words  Ассоц. массив со словами, которые были исправлены:
	 *                                 в ключах оригиналы, в значениях исправленные слова.
	 * @return  string|bool            Returns FALSE if error occured
	 */
	public function parse($s, $mode = self::SIMILAR_CHARS, array &$words = null)
	{
		if (! ReflectionTypeHint::isValid()) return false;
		if (! is_string($s)) return $s;

		if ($mode < self::SIMILAR_CHARS || $mode > (self::SIMILAR_CHARS | self::KEYBOARD_LAYOUT | self::ADD_FIX))
		{
			trigger_error('Unknown mode', E_USER_WARNING);
			return false;
		}

		$this->mode = $mode;

		#вырезаем и заменяем некоторые символы
		$additional_chars = array(
			"\xc2\xad",  #"мягкие" переносы строк (&shy;)
		);
		#http://ru.wikipedia.org/wiki/Диакритические_знаки
		$s = UTF8::diactrical_remove($s, $additional_chars, $is_can_restored = true, $restore_table);

		$this->words = array();
		$s = $this->_parse1($s);
		$s = $this->_parse2($s);
		$s = UTF8::diactrical_restore($s, $restore_table);
		$words = $this->words;
		return $s;
	}

	private function _parse1($s)
	{
		#заменяем слова из текста, минимальная длина -- 3 символа, меньше нельзя
		return preg_replace_callback('/(?> (' . $this->en . ')  #1 латинские буквы
                                         | (' . $this->tt . ')  #2 русские буквы
                                         | (' . $this->sc . ')  #3 символы, которые м.б. набраны по ошибке в английской раскладке клавиатуры вместо русских букв
                                       ){3,}+
                                      /sxSX', array($this, '_word'), $s);
	}

	private function _parse2($s)
	{
		#исправляем русские буквы (похожие на латинские) с рядом стоящими цифрами на латинские
		#например, это м. б. каталожные номера автозапчастей, в которых есть русские буквы: 1500A023, 52511-60900-H0, K2305, XA527672
		#корректно обрабатываем вхождения '1-ое', 'Ту-134', 'А19-3107/06-43-Ф02-4227/06-С1'
		if (version_compare(PHP_VERSION, '5.2.0', '<')) return $s;
		return preg_replace_callback('~(?: (?<=[^-_/]|^)
                                           (?:' . $this->ru_similar . ')++
                                           (?= (?:' . $this->en . '|[-_/])*+ (?<=[^-_/]|' . $this->en . '[-_/])
                                               \d [\d-_/]*+ (?!' . $this->tt_uniq . ')
                                           )
                                         | (?<=[^-_/]|^)
                                           \d  (?:' . $this->en . '|[-_/])*+ (?<=[^-_/]|' . $this->en . '[-_/])
                                           \K
                                           (?:' . $this->ru_similar . ')++
                                           (?= [\d-_/]*+ (?!' . $this->tt_uniq . ') )
                                       )
                                      ~sxSX', array($this, '_entry'), $s);
	}

	private function _entry(array &$a)
	{
		$entry =& $a[0];
		$s = strtr($entry, $this->table[0]);
		if ($s !== $entry) $this->words[$entry] = $s;
		return $s;
	}

	private function _word(array &$a)
	{
		$word = $a[0];
		#var_export($a);

		$suggestions = array();

		#если найдено слово из мешанины русских и латинских букв
		if (! empty($a[1]) && ! empty($a[2]))
		{
			if (($this->mode & self::SIMILAR_CHARS) === 0) return $word;
			#ВНИМАНИЕ! порядок следования правил преобразования имеет значение!

			/*
            Исправляем ошибочно набранные буквы, которые выглядят одинаково
            в инициалах перед фамилиями (русский <--> английский), например: Т.С.Навка
			*/

			#0a. английский --> русский:
			if (substr($word, 1, 1) === '.'  #оптимизация
				&& preg_match('/^ (  ' . $this->en_similar_uc . '\.         #первый инициал
                                     (?:' . $this->en_similar_uc . '\.)?    #второй инициал (необязательно)
                                  )                                       #1 инициалы
                                  (' . $this->no_sc . '{2,}+)             #2 фамилия (английские и русские буквы)
                                $/sxSX', $word, $m))
			{
				$m[2] = $this->_parse1($m[2]);
				#фамилия по-русски?
				if (preg_match('/^ (?:' . $this->tt_uc  . ')   #первая буква д.б. большая
                                   (?:' . $this->tt_f   . ')+  #минимальное кол-во букв в фамилии = 2
                                 $/sxSX', $m[2])) return strtr($m[1], $this->table_flip[0]) . $m[2];
			}

			#0b. русский --> английский:
			if (substr($word, 2, 1) === '.'  #оптимизация
				&& preg_match('/^ (  ' . $this->ru_similar_uc . '\.         #первый инициал
                                     (?:' . $this->ru_similar_uc . '\.)?    #второй инициал (необязательно)
                                  )                                       #1 инициалы
                                  (' . $this->no_sc . '{2,}+)              #2 фамилия (английские и русские буквы)
                                $/sxSX', $word, $m))
			{
				$m[2] = $this->_parse1($m[2]);
				#фамилия по-англ.?
				if (preg_match('/^ ' . $this->en_uc  . '  #первая буква д.б. большая
                                   ' . $this->en . '++    #минимальное кол-во букв в фамилии = 2
                                 $/sxSX', $m[2])) return strtr($m[1], $this->table[0]) . $m[2];
			}

			#1. английский --> русский:
			$this->method = 0;  #буквы, которые выглядят одинаково
			$this->is_flip = true;
			$s = $this->_replace($word, $this->tt_correct);
			if ($word !== $s && ! $this->_is_mixed($s)) $suggestions['tt0'] = $s;

			#2. английский --> русский:
			$this->method = 1;  #буквы в другой раскладке клавиатуры
			$this->is_flip = true;
			$s = $this->_replace($word, $this->tt_correct);
			if ($word !== $s) $suggestions['tt1'] = $s;

			#3. русский --> английский:
			$this->method = 0;  #буквы, которые выглядят одинаково
			$this->is_flip = false;
			$s = $this->_replace($word, $this->en_correct);
			if ($word !== $s && ! $this->_is_mixed($s)) $suggestions['en0'] = $s;

			#4. русский --> английский:
			$this->method = 1;  #буквы в другой раскладке клавиатуры
			$this->is_flip = false;
			$s = $this->_replace($word, $this->en_correct);
			if ($word !== $s) $suggestions['en1'] = $s;

		}
		#если найдено слово только из латинских букв; минимальная длина -- 4 буквы!
		elseif (! empty($a[1]) && strlen($word) >= 4)
		{
			if (($this->mode & self::KEYBOARD_LAYOUT) === 0) return $word;

			#не обрабатываем аббревиатуры, пример: AMPAS
			if (preg_match('/^(?:' . $this->en_uc . '|' . $this->sc . '){1,6}+$/sxSX', $word)) return $word;

			#английский --> русский:
			$suggestions['en1'] = $word;
			$suggestions['tt1'] = strtr($word, $this->table_flip[1]);
		}
		#если найдено слово только из русских букв; минимальная длина -- 4 буквы!
		elseif (! empty($a[2]) && strlen($word) >= 8)
		{
			if (($this->mode & self::KEYBOARD_LAYOUT) === 0) return $word;

			#не обрабатываем аббревиатуры, пример: ДОСААФ
			if (preg_match('/^(?:' . $this->tt_uc . '|' . $this->sc . '){1,6}+$/sxSX', $word)) return $word;

			#русский --> английский:
			$suggestions['tt1'] = $word;
			$suggestions['en1'] = strtr($word, $this->table[1]);
		}
		#найдены спецсимволы или длина слова слишком мала
		else return $word;

		$suggestions = array_unique($suggestions);
		#var_export($suggestions);

		$c = count($suggestions);
		if ($c === 0) $s = $word;
		else $s = $this->_detect($word, $suggestions, ! empty($a[3]));
		if ($s !== $word)
		{
			$this->words[$word] = $s;
			if ($this->mode >= (self::KEYBOARD_LAYOUT | self::ADD_FIX)) $s = '(' . $word . '=>' . $s . ')';
		}
		return $s;
	}

	private function _replace($word, $regexp)
	{
		do $word = preg_replace_callback($regexp, array(&$this, '_strtr'), $w = $word);
		while ($w !== $word);
		return $word;
	}

	private function _strtr(array $a)
	{
		$word =& $a[0];
		return strtr($word, $this->is_flip ? $this->table_flip[$this->method] : $this->table[$this->method]);
	}

	private function _is_mixed($word)
	{
		return preg_match('/(?:' . $this->en    . ')/sxSX', $word) &&
			preg_match('/(?:' . $this->tt_f  . ')/sxSX', $word);
	}

	#выбираем из нескольких вариантов один
	private function _detect($word, array $suggestions, $is_sc)
	{
		if (0) #DEBUG
		{
			//$suggestions['?'] = $word;
			var_export($suggestions);
		}
		#не д. б. несуществующих N-грамм
		foreach ($suggestions as $type => $w)
		{
			$lang = substr($type, 0, 2);
			if ($this->_bigram_exists($w, $lang)) unset($suggestions[$type]);
		}
		if (0) #DEBUG
		{
			//$suggestions['?'] = $word;
			var_export($suggestions);
		}
		if (count($suggestions) === 0) return $word;

		$s = end($suggestions);

		#если в $word были спецсимволы, а в $s их уже нет, возвращаем $s
		if ($is_sc && ! preg_match('/' . $this->sc . '/sSX', $s)) return $s;
		
		#если в $s спецсимволов больше чем букв, возвращаем $word
		$sc_count = 0;
		$s = preg_replace('/' . $this->sc . '/sSX', '', $s, -1, $sc_count);
		if ($sc_count > 0 && $sc_count > UTF8::strlen($s)) return $word;

		return reset($suggestions);
	}

	#анализ на основе N-грамм русского и английского языка
	private function _bigram_exists($word, $lang)
	{
		$word = ($lang === 'en') ? strtolower($word) : UTF8::lowercase($word);

		#шаг 0.
		#проверяем слова в списке слов-исключений
		if (array_key_exists($word, $this->words_exceptions[$lang])) return false;

		#шаг 1.
		#проверка на 4 согласные буквы подряд; пример: больши{нств}о, юрисконсу{льтс}тво
		if (preg_match('/(?:' . $this->consonant_lc[$lang] . '){4}/sxSX', $word, $m)
			#проверяем список исключений
			&& ! array_key_exists($m[0], $this->consonants4_lc[$lang])) return true;

		#шаг 2.
		#проверка на 3 гласные буквы подряд; пример: длиннош{еее}, зм{еео}бразный
		if (preg_match('/(?:' . $this->vowel_lc[$lang] . '){3}/sxSX', $word, $m)
			#проверяем список исключений
			&& ! array_key_exists($m[0], $this->vowels3_lc[$lang])) return true;

		#шаг 3.
		$length = UTF8::strlen($word);
		for ($pos = 0, $limit = $length - 1; $pos < $limit; $pos++)
		{
			/*
            TODO  Качество проверки по несуществующим биграммам можно немного повысить,
            если учитывать не только начало и конец слова, но и все позиции биграмм в слове.
			*/
			$ss = UTF8::substr($word, $pos, 2);
			if ($pos === 0)              $ss = ' ' . $ss;  #beginning of word
			elseif ($pos === $limit - 1) $ss = $ss . ' ';  #ending of word
			if (array_key_exists($ss, $this->bigrams)) return true;
		}

		return false;
	}
}